﻿#ifndef HEADER_9D47430B27D7D62
#define HEADER_9D47430B27D7D62

#ifndef _XTFS_RECORD_INFO_
#define _XTFS_RECORD_INFO_

#include "crossplat_def.h"
//#include "STFS_com.h"
#include "storage_api.h"
//定义帧头信息结构体
#ifdef _WIN32
#define DEVICE_VER      "WIN32 SIMULATE RECORDER"  //模拟录像器
#define INTERNAL_VER    "V1.0.0"


#define DEBUG_ERROR(module, format,...)

#define DEBUG_WARNING(module, format,...)

#define DEBUG_INFO(module, format,...)

#else
#include "media_frame_hd.h"
#define DEVICE_VER      "CV3100 BUS DVR"  //模拟录像器
#define INTERNAL_VER    "V2.0.0"
#endif

//保证录像信息头对齐对512字节，
#pragma pack(push)
#pragma pack(4)
typedef struct _STFS_REC_FILEHEAD_
{
	char	 magic[8];					//录像文件标识
	uint32_t version;					//录像文件版本
	uint32_t fileSpace;					//文件的实际空间
	uint32_t fileLen;					//文件实际大小
	uint16_t channel;
	uint16_t offset_convert;			//文件索引倒置　　　　0:表示正常　1：表示倒置
	uint32_t indexNO;					//每个预分配文件的编号
	uint32_t recordSN;                  //录像文件序列号

	int64_t  startTime;					//开始时间
	int64_t  endTime;					//结束时间

	uint32_t recOffset;					//多录像段的信息
	uint32_t recNum;
	uint32_t idxOffset;					//索引的偏移
	uint32_t idxNum;					//索引总数

	uint32_t dataOffset;				//数据区的偏移

	//设备信息
	uint32_t deviceID;					//设备编号
	char	deviceSN[MAX_DESC_LEN];		//设备序列号
	char	deviceName[MAX_DESC_LEN];	//设备名称
	char	softVersion[MAX_DESC_LEN];	//软件版本
	uint32_t frameRate;                 //视频帧率
	uint16_t writeStatus;				//录像状态　
	uint16_t chk_sig;					//校验
	
	//2017-11-16 10:19:11 循环录像的旧录像段信息,如果文件正常录像完成，就不存在

	uint16_t bCover;                    //存在旧的录像段
	uint16_t old_ch;					//旧的录像通道                    
	int64_t  old_startTime;				//开始时间
	int64_t  old_endTime;				//结束时间
// 	//****记得每次修改结构体后，需要保证结构对齐到512，
// 	char reserveData[512-256];			//起到补齐整个结构的作用
// 	//****记得每次修改结构体后，需要保证结构对齐到512 　去掉当前不好的设计，底层的接口已经做了对齐处理．

}STFS_REC_FILEHEAD,*PSTFS_REC_FILEHEAD;
#pragma pack(pop)

typedef struct _STFS_REC_EXTERN_
{
	uint32_t recordSN;                  //录像文件流水号
	uint32_t deviceID;					//设备编号
	char	deviceSN[MAX_DESC_LEN];		//设备序列号
	char	deviceName[MAX_DESC_LEN];	//设备名称
	char	softVersion[MAX_DESC_LEN];	//软件版本
	int vWidth;						  //视频宽高
	int vHeight;		              
	uint32_t vRate;                 //视频帧率
	uint32_t asfPacketSz;	        //ASF文件打包大小
	int video_enc_fmt;				//视频编码格式，默认0 为H264 1. H265
	int audio_channels;				//音频通道
	int audio_rate;					//音频比特率
	int audio_bit;					//音频位宽
	int audio_fmt;					//音频格式
	char video_fmt[8];              //视频编码格式
}STFS_RECINFO_EXTERN,*PSTFS_RECINFO_EXTERN;


//录像段 64字节保证
typedef struct _STFS_SEGMENT_
{
	int      type;			//录像类型
	uint32_t dataLen;		//数据长度
	uint32_t segNO;			//录像段
	uint32_t idxNum;		//包含的I帧索引项总数

	int64_t  tmStart;		//标准时间
	int64_t  tmEnd;			//标准时间

	uint32_t idx_startNo;;	//起始I帧在I帧索引区的编号
	uint32_t data_endpos;	//起始数据在数据区的偏移
	uint32_t data_start;	//录像段开始
	//44
	char	 reserved[16];	//保留，可以设计成存储字符串
	uint32_t magic;
}STFS_REC_SEG,*PSTFS_REC_SEG;

//录像索引音视频混合索引 占用24字节
//2017-10-24 16:27:29 重新设计 帧长度基本上单帧不会超10M  24字节（65536 * 256 ）

typedef struct _REC_INDEX_
{
	uint32_t  magic;		//索引标记
	uint16_t   NO;			//编号
	uint8_t   frameType;	//数据流类型
	uint8_t   isCorrect;	//是否被校正
	int64_t   tmMS:42;		//标准时间 MS 
	uint32_t   frameLen:22;	//帧长度
	uint32_t  offset;		//文件中的位置
}STFS_REC_IDX;

typedef struct _REC_INDEX_GPS_
{
	uint32_t magic;			//GPS标记
	uint8_t  idxSize;		//索引大小　20byte
	uint8_t  gpsValid;   	//0: gps无效
	uint8_t  frameType;		//数据流类型
	uint8_t  speed;      	//车速, Km/h
	int64_t  tmMS:42;		//标准时间
	int32_t  latitude:22;	//纬度值,最高位是0: 北纬; 最高位是1,南纬
	int32_t  longitude;     //经度值,最高位是0: 东经; 最高位是1,西经
}STFS_GPS_IDX;

#if 0
typedef struct _REC_INDEX_
{
	uint32_t  magic;		//索引标记
	uint16_t   NO;			//编号
	uint8_t   frameType;	//数据流类型
	uint8_t   isCorrect;	//是否被校正
	uint32_t  tmSec;		//标准时间
	uint32_t  frameLen;		//帧长度
	uint32_t offset;		//文件中的位置
}STFS_REC_IDX;
typedef struct _REC_INDEX_GPS_
{
	uint32_t magic;			//GPS标记
	uint8_t  idxSize;		//索引大小　20byte
	uint8_t  gpsValid;   	//0: gps无效
	uint8_t  frameType;		//数据流类型
	uint8_t  speed;      	//车速, Km/h
	uint32_t tmSec;			//单位秒
	int32_t  latitude;   	//纬度值,最高位是0: 北纬; 最高位是1,南纬
	int32_t  longitude;     //经度值,最高位是0: 东经; 最高位是1,西经
}STFS_GPS_IDX;
#endif


typedef enum _record_file_status_
{
	RECORD_FILE_UNUSED = 0,		//未使用
	RECORD_FILE_USED   = 0x01,	//正常使用中（未锁定、未隐藏）
	RECORD_FILE_LOCK   = 0x02,	//被锁定
	RECORD_FILE_HIDE   = 0x04,	//被隐藏
	//extern　status
	RECORD_FILE_MARGED   = 0x40, //
	RECORD_FILE_RESTORE_FAIL = 0x2F,//需要回收利用的录像文件

	RECORD_FILE_RECORDING = 0x80,//处于正在录像的状态

}E_RECORD_FILE_STATUS;

//录像索引文件
typedef enum
{
	FILE_NO_USE = 0,
	FILE_USBED,
	FILE_BADSETOR,	//文件存在坏扇区
}FILE_STATUS;

#pragma pack(4)
typedef struct _STFS_INDEX_INFO_
{
	char idxMagic[8];					//签名
	uint32_t	version;				//该文件的版本号

	uint32_t	diskInfoOffset;			//磁盘信息区域偏移（每个录像文件对应一段）
	uint32_t	diskInfoLen;			//磁盘信息单位长度

	uint32_t    recFileSize;			//单个录像文件大小
	uint32_t	indexInfoOffset;		//存储区索引信息偏移位置
	uint32_t	indexLength;			//每个区块长度，可能不同产品格式化不一样长度（MB）
	uint32_t	indexInfoNum;			//存储区索引数目（即多少个存储单位）

	uint32_t	indexInfoBaseLen;		//每个存储区索引基本描述信息
	//录像段信息
	uint32_t	recInfoOffset;			//文件记录相对于对应地索引信息偏移位置
	uint32_t	recInfoLen;				//每条文件记录的长度（用于兼容不同地结构体）
	uint32_t	recInfoNum;				//预留存储空间可写的记录数目（文件记录）

	uint32_t	fileSize;				//整个索引文件的大小

	uint32_t    createTm;				//创建时间
	uint32_t	changeTm;				//修改时间

	uint32_t    sptMaxCH;				//支持的最大通道数
	uint64_t    baseRecFileLBA;			//首个预分配录像文件的地址

	uint32_t	reserveData[128 - 10];	//保证对齐到512字节
	uint32_t	checkSum;				//crc校验和
}ST_INDEX_FILE_INFO,*PST_INDEX_FILE_INFO;		//

//设计的是从4K位置开始,主要是记录时间大范围往回跳变, 导致的录像重叠
typedef struct _STFS_INDEX_DSYINFO_
{
	char dstInfoMagic[8];					//签名


}STFS_INDEX_DSYINFO,*PSTFS_INDEX_DSYINFO;

//36BYTE
typedef struct _STFS_rec_index_info_
{
	uint8_t			dataSource;		//流编号 E_SOURCE_TYPE
	uint8_t 		channel;		//通道号
	uint8_t			segmentCnt;		//录像段总数
									//当录像段只有一个的时候，就会把状态存储一个字节当中
	uint8_t			lockCnt;		//锁定文件的计数器
	uint8_t			oneSegStatus;	//录像状态 当只存在一个录像段时才有效，便于加速录像索引
	uint8_t         timeZone;		//2017年5月28日 记录时区
	uint16_t		oneSegType;		//录像类型 当只存在一个录像段时才有效，便于加

	uint32_t 		totalSize;	 	//文件大小
	uint32_t 		indexNo;		//索引序号

	int64_t			startTime;		//起始时间
	int64_t			endTime;		//结束时间
	uint32_t        recordSN;       //流水编号  所有录像文件都会有编号， 0 - 65536 * 65536
}STFS_RECIDX_BASEINFO;


//单条索引记录的头信息
typedef struct index_info
{
	STFS_RECIDX_BASEINFO baseInfo;	//基本信息
	char			text[28];		//仅有一段录像时这里会存储字符串，

	uint32_t		deviceID;		//设备编号
	uint32_t		cameraID;		//摄像机编号

	char			deviceSN[MAX_DESC_LEN];		//设备序列号
	char			deviceName[MAX_DESC_LEN];	//设备名称
	char			cameraName[MAX_DESC_LEN-12];	//通道名称
	uint32_t		chksum;		//摄像机编号
}INDEX_INFO_HEAD,*PINDEX_INFO_HEAD;  //纠正之前的不良的设计，将结构扇区对齐到512字节，避免无端的空间浪费．

//索引中录像段信息
typedef struct _record_segment_
{
	uint16_t	status;		//状态：
	uint8_t     dataSource; //录像流属性
	uint8_t	    enableText;	//是否使用文本信息(只读）

	uint32_t	length;		//文件数据长度(KB)
	uint16_t	type;		//录像类型  //uint32_t	type;		//录像类型
	uint16_t    timeZone;  //时区      增加时区

	int64_t		startTime;	//起始时间
	int64_t		endTime;	//结束时间
	uint32_t	endOffset;	//文件结束偏移
//	uint32_t    startOffset;//录像段开始位置 // 不可靠，因为回放时需要定位I帧后才能够播放录像
	char		text[28];	//文本内容
}REC_SEGMENT_S,*PREC_SEGMENT_S;

//需要写入到索引文件里面的信息
typedef struct _rec_write_info_
{
	uint32_t	indexNo;				//区块索引
	uint32_t	segIndex;				//当前区块中文件记录偏移

	uchar_t		dataBuf[SIZE_4KB];		//索引记录缓冲

#if 0
	INDEX_INFO_HEAD		indexInfo;		//索引头信息
	REC_SEGMENT_S		fileInfo;		//录像段信息
#endif
}REC_WRITE_INFO,*PREC_WRITE_INFO;


enum REC_FILE_TYPE
{
	F_NOR_REC    = 0,       //通用录像文件
	F_NOR_REC_FORAPP,       //通用录像文件方便app传输,480P

	F_EVT_REC,             //紧急录像文件
	F_EVT_REC_FORAPP,      //紧急录像文件方便app传输，480P

	F_THUMBNAIL_DIR,	   //录像文件缩略图目录

	F_PHO_CAPTURE,         //抓拍和图片

};

enum FILE_BOX_TYPE
{
	FBOX_AVI = 0, //AVI文件
	FBOX_MP4,
	FBOX_ASF,
	FBOX_STFS,    //私有格式
};

#define SWITCH_BY_TIME       0 
#define SWITHC_BY_SZMB     1

//内存中存放，方便循环覆盖使用
typedef struct _RECFILE_INFO_
{
	uint8_t  status; 
	uint8_t  reserve; //保留，以便于4字节对齐
	uint8_t  channel;
	uint8_t  fileType;   //REC_FILE_TYPE

	uint32_t length;	 //录像长度
	time_t   tmStartSec;   //文件开始时间
	time_t   tmEndSec;     //文件结束时间
}RECFILE_INFO,*PRECFILE_INFO;

#include <vector>
using namespace std;

#pragma pack()

/***************************************************************/
//定义录像文件信息头

#define FZD_RECORD_MAGIC {0x46, 0x5A, 0x44, 0x20, 0x52, 0x45, 0x43, 0x44}	//FZD RECD

const uint32_t STFS_RECORD_VERSION = mmioFOURCC('0','2','0','0');			//Serial Turbo V2.00
;
//串行加速文件系统 Serial Turbo File System
#define STORAGE_FS_FLAG        *(U32*)"STFS"

#define  INDEX_BASE_LBA		   0x2000
#define  RECORD_BASE_LBA       2048		//第一个录像文件的起始地址

//录像文件信息				52 45 43 44
#ifdef _WIN32
#define STFS_MAX_CHANNEL	   32
#else
#define STFS_MAX_CHANNEL	   32
#endif

#define STFS_RECORD_SPACE	      SIZE_MB(512)
#define STFS_RECORD_MAGIC        {0x53,0x54,0x46,0x53,0x52,0x45,0x43,0x44} // "STFSRECD"

#define STFS_REC_SEG_OFFSET       512
#define STFS_REC_IDX_OFFSET       SIZE_8KB
#define STFS_REC_DATA_OFFSET      SIZE_KB(188)	//(128 + 60) KB
#define STFS_REC_IDX_SIZE         STFS_REC_DATA_OFFSET - STFS_REC_IDX_OFFSET
#define STFS_REC_IDX_CORRECTED      1
#define STFS_REC_IDX_NORMAL         0
#define STFS_REC_INIT_HEAD        0x0000	//已经初始化完成
#define STFS_REC_WRITTING	      0x1111	//正在写入
#define STFS_REC_WT_APPEND		  0x1123    //追加写入
#define STFS_REC_END_FLAG	      0x6666	//666顺 表明正常结束

#define STFS_REC_IDX_SIG	      mmioFOURCC('R','I','D','X')//索引标识
#define STFS_GPS_IDX_SIG	      mmioFOURCC('G','P','S','I')//GPS INFO
#define STFS_REC_SEG_SIG		  mmioFOURCC('R','S','E','G')//录像段标识
#ifdef _WIN32
#define STFS_REC_TIME_JUMP		  60000		//跳变时间 ,大于30秒则切换文件
#else
#define STFS_REC_TIME_JUMP		  60000		//跳变时间 ,大于10秒则切换文件
#endif
#define STFS_REC_LEAST_SPACE	  SIZE_MB(8) //保证录像段文件有8MB的空间去存储录像
//#define STFS_NODATAFLAG_DIFFTM  3000		//超过1分钟没有取到数据
#define STFS_CREATESEG_DIFFTM	   30000	//超过30分钟没有取到数据
#define STFS_CREATESEG_DIFFTM_MS   15000		//超过15S钟没有取到数据
#define STFS_NONE_DSTJUMP          0        //没有发生时间跳变
#define STFS_REPLAYBUF_FULL		   100      //回放数据缓冲满了
#define STFS_ONEDAY_MS			(24*60*60)*1000 //一天的总共毫秒数
#define STFS_ONEDAY_SEC			(24*60*60) //一天的总共秒数
#define STFS_ONEHOUR_SEC		(1*60*60)   //一小时的总共秒数
#define STFS_HONR_SEC(X)         (X*60*60)  //N小时间的秒数
#define STFS_LOCAL_CLIENTID			0		//本地用户ＩＤ
//索引文件记录
//#define INDEX_INFOSIZE		   4096			//单条4KB

#define INDEX_DISK_INFO_OFFSET 1024     //磁盘信息描述
#define INDEX_DISK_INFO_LEN    1024		//控制在1KB以内
#define INDEX_DSTINFO_OFFSET   0x1000   //夏令时导致的时间跳信息
#define INDEX_INFO_OFFSET	   0x8000	//32K开始
#define INDEX_BASEINFO_OFFSET  256

#define STFS_INDEX_MAGIC       {0x53,0x54,0x46,0x53,0x20,0x49,0x44,0x58} // "STFS IDX"
#define STFS_INDEX_VERSION	    mmioFOURCC('0','0','1','0');
#define STFS_INDEX_VERSION_0D11 mmioFOURCC('0','0','1','1');
#define STFS_INDEX_VERSION_0D12 mmioFOURCC('0','0','1','2');

#define STFS_RECORDTYPE_ALL    -1
#define STFS_ALL_STREAMID      -1
#define STFS_ALL_CLIENTID	   -1

#define MAGIC_LEN			   8
#define STFS_1SEC_MS		   1000
#define STFS_1DAY_SECS         24*60*60
#define STFS_1DAY_MS           24*60*60*1000
#define STFS_CREATE_IDX_MS     980
#define STFS_CREATA_PIDX_MS    4000     //索引
#define STFS_IFRM_MAXDIFF_MS   4000     //I帧间隔最大不会超过4秒
#define STFS_ALL_CHANNEL	   -1
#define STFS_ALL_USERID		   -1
#define STFS_READBUF_FULL      100
#ifdef _WIN32
#define STFS_RECORCD_MERGEMS   5000     //时间小于1秒忽略掉，合并两段录像类型相同的
#else
#define STFS_RECORCD_MERGEMS   1000     //时间小于1秒忽略掉，合并两段录像类型相同的
#endif
#define STFS_RECORD_LITTLE     3000    //较短的录像段

#define STFS_ALRAM_LEASTSECS   5
#define STFS_ALARM_RECTIME	   30
#define STFS_MERGE_RECTIME	   10  //10
#ifdef _WIN32
#define STFS_GETFRM_BUFSIZE	   SIZE_KB(1000)
#else
#define STFS_GETFRM_BUFSIZE	   SIZE_KB(256)
#endif
#define STFS_TELNET_BASEID      1
#define STFS_MAXSPT_CLIENT	   (4 + 1)	//本地用户+四个网络用户名
#ifdef _WIN32
#define STFS_PREPARE_BUF_NUM	  4
#else
#define STFS_PREPARE_BUF_NUM	  4
#endif
#define STFS_REPLAY_IFRAME_STEP     1
#define STFS_CLIENT_UNUSE	        -1		//未使用
#define STFS_DIFF_SEARCH_SEC        3		//间隔
#define STFS_DIFF_SEARCH_SEC_TELNET 15		//考虑有网络延时，尽量少去频繁搜索录像，减少磁盘读取次数。
#define STFS_SUPPORT_VEDIO_HE                      960
#define DEF_UDISK_PATH    "/mnt/udisk/"
#define  RP_ALIGNBUF_SIZE	SIZE_KB(512)
//备份目录
#ifdef _WIN32
#define STFS_BACKUP_DIR	      "FoscamNVR\\"
// #ifdef TRACE
// #undef TRACE
// #define TRACE g_log.Out
// #endif


#ifdef TRACE_DBG
#undef TRACE_DBG
#define TRACE_DBG g_log.Out
#endif

#ifdef DEBUG_INFO
#undef DEBUG_INFO
#define DEBUG_INFO
#endif


#else
#define STFS_BACKUP_DIR	      "LongHornDVR/"
#endif
#define _HAVE_EXTERN_INFO_
#ifdef _HAVE_EXTERN_INFO_
#define STR_NVR_DEVNAME	      "FN3104H"
#endif

//#define  _LOOK_TIME_

//常量
const int REC_HEADINFO_LEN    =  sizeof(STFS_REC_FILEHEAD);
const int REC_INDEX_LEN       =  sizeof(STFS_REC_IDX);
const int GPS_INDEX_LEN       =  sizeof(STFS_GPS_IDX);
const int REC_SEG_LEN         =  sizeof(STFS_REC_SEG);
const int REC_SEG_LEN_OF_IDX  =  sizeof(REC_SEGMENT_S);

const uint32_t STFS_MAX_RECIDX_NUM = (STFS_REC_DATA_OFFSET - STFS_REC_IDX_OFFSET)/REC_INDEX_LEN;
#ifdef _WIN32
const uint32_t STFS_MAX_SEG_NUM	  = (SIZE_4KB - INDEX_BASEINFO_OFFSET)/sizeof(REC_SEGMENT_S);
#else
const uint32_t STFS_MAX_SEG_NUM	  = (SIZE_4KB - INDEX_BASEINFO_OFFSET)/sizeof(REC_SEGMENT_S);
#endif
#define FRM_HEAD_LEN		   52

const int INDEX_BASEINFO_LEN  = sizeof(INDEX_INFO_HEAD);
const int INDEX_INFOSIZE	  = 4096;			//单条4KB

const int MAX_SEARCH_REC	  = 65536;
const int64_t STFS_REC_MAX_TIMEMS  = ((int64_t)0x7FFFFFFF) * 1000;
#define  STFS_REC_FILE_SIZEMB    128
const uint32_t DEF_RECORD_SIZE    = SIZE_MB(128);

#endif //_XTFS_RECORD_INFO_

#endif // header guard
